﻿using System;
using Core.AbstractEntities;
using Lexicon;
using Types;

namespace Operations.Entities
{
    /// <summary>
    /// Analyse the element added in the stack
    /// </summary>
    public class AnalysisLexical
    {
        private Lexicon.Lexicon Lexer { get; set; }
        private Lexicon.CommandBinay CommandBinary { get; set; }
        private Lexicon.CommandUnitary CommandUnitary { get; set; }
        private Lexicon.StartOfExpressionCollection StartOfExpressionCollection { get; set; }
        private Lexicon.EndOfExpressionCollection EndOfExpressionCollection { get; set; }
        private Lexicon.StartOfListCollection StartOfListCollection { get; set; }
        private Lexicon.EndOfListCollection EndOfListCollection { get; set; }

        /// <summary>
        /// Constructor by default
        /// </summary>
        public AnalysisLexical()
        {
            Lexer = Lexicon.Lexicon.Instance;
            CommandBinary = Lexer.Expression.CommandCollection.CommandBinary;
            CommandUnitary = Lexer.Expression.CommandCollection.CommandUnitary;
            StartOfExpressionCollection = Lexer.Expression.StartOfExpressionCollection;
            EndOfExpressionCollection = Lexer.Expression.EndOfExpression;
            StartOfListCollection = Lexer.Expression.StartOfListCollection;
            EndOfListCollection = Lexer.Expression.EndOfListCollection;
        }

        /// <summary>
        /// Specify if the element is : int,  double
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsNumeric(HpElement element)
        {
            return element.Type == typeof(int) ||
                element.Type == typeof(double);
        }

        /// <summary>
        /// Specify if the element is un program RPL. I.e. "« DUP IF 180  »"
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsRPL(HpElement element)
        {
            return
                element.Type == typeof(Rpl)
                &&
                (element.Value.ToString()).StartsWith(this.StartOfExpressionCollection[0].Value)
                &&
               (element.Value.ToString()).EndsWith(this.EndOfExpressionCollection[0].Value);
        }

        /// <summary>
        /// Specify if the element is a linear list  {25 5 8 13}
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsList(HpElement element)
        {
            return
                element.Value.ToString().StartsWith(this.StartOfListCollection[0].Value)
                &&
                element.Value.ToString().EndsWith(this.EndOfListCollection[0].Value);
        }


        /// <summary>
        /// Specify if the element is an unitary operator 
        /// for instance : 
        ///  2 !          i.e. "!"  
        ///  3.1415 DUP   i.e. "DUP"  
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsCommandUnitary(HpElement element)
        {
            foreach (Token token in this.CommandUnitary)
            {
                if (token.Value == element.Value.ToString())
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Specify if the element is an binary operator 
        /// for instance : 
        ///  25 4 *  i.e. "*"  
        ///  76 2 +  i.e. "+"
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsCommandBinary(HpElement element)
        {
            foreach (Token token in this.CommandBinary)
            {
                if (token.Value == element.Value.ToString())
                    return true;
            }
            return false;
        }


        /// <summary>
        /// Specify if the element added is a primitive type
        /// for instance : int, string, double, char
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsPrimitive(HpElement hpElement)
        {
            Object element = hpElement.Value;

            if ((!IsList(hpElement) 
                && (!IsCommandBinary(hpElement) && !IsCommandUnitary(hpElement)))
                && !IsRPL(hpElement))
            {
                if (Type.Equals(element.GetType(), Int32.MaxValue.GetType()))
                    return true;
                if (Type.Equals(element.GetType(), String.Empty.GetType()))
                    return true;
                if (Type.Equals(element.GetType(), Double.MinValue.GetType()))
                    return true;
                if (Type.Equals(element.GetType(), Char.MaxValue.GetType()))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Specify if the element implies an operation Binary or Unitary, it's a combination of IsCommandUnitary and IsCommandBinary
        /// for instance : 
        ///  2 !
        ///  3.1415 DUP
        ///  25 4 *  i.e. "*"  
        ///  76 2 +  i.e. "+" 
        /// </summary>
        /// <param name="element">Item of the stack</param>
        public bool IsOperation(HpElement hpElement)
        {
            return (this.IsCommandBinary(hpElement) || this.IsCommandUnitary(hpElement));
        }
    }
}
